package com.items.form.base;


import com.items.form.model.TFormTable;
import com.items.form.model.TFormValue;

import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 动态表单抽象服务
 *
 * @author bai
 * @date 2023/02/08
 */
public abstract class DynamicServiceAbs<E> implements IDynamicService<E> {

    private final Class<E> tClass;

    public final  String tableName;

    private final Field[] fields;

    private final static String rowId = "rowId";

    private Field rowIdField;

    public final static int fieldLength = 20;

    /**
     * 排除的字段
     */
    private final static String[] exFields = {"serialVersionUID"};

    public AbsDynamicService(Class<E> tClass){
        this(tClass.getName(), tClass);
    }

    public AbsDynamicService(String tableName, Class<E> tClass){
        this.tClass = tClass;
        this.tableName = tableName;
        Field[] tempField = tClass.getDeclaredFields();
        Set<Field> fieldList = new HashSet<>();
        Class<? super E> cls = tClass.getSuperclass();
        while (cls != null){
            if (cls == Object.class){
                break;
            }
            setFields(fieldList, cls.getDeclaredFields());
            cls = cls.getSuperclass() ;
        }
        setFields(fieldList, tempField);
        this.fields = fieldList.toArray(new Field[0]);
    }

    public void setFields(Set<Field> fieldList, Field[] Fields){
        for(Field field: Fields){
            boolean isAdd = true;
            for (String f: exFields){
                if (field.getName().equals(f)){
                    isAdd = false;
                    break;
                }
            }
            if (isAdd){
                fieldList.add(field);
                field.setAccessible(true);
                if (field.getName().equals(rowId)){
                    this.rowIdField = field;
                }
            }
        }
    }


    public List<TFormTable> getTableInit(List<TFormTable> formTables){
        LocalDateTime localDateTime = LocalDateTime.now();
        List<TFormTable> list = new ArrayList<>();
        for(Field field: fields){
            TFormTable f = new TFormTable();
            Optional<TFormTable> first  = formTables.stream().filter(item->item.getTableField().equals(field.getName())).findFirst();
            first.ifPresent(tFormTable -> f.setId(tFormTable.getId()));
            f.setTableField(field.getName());
            f.setTableName(tableName);
            f.setTableFieldType(field.getType().getTypeName());
            f.setCreateTime(localDateTime);
            list.add(f);
        }
        return list;
    }

    public List<TFormValue> getAddFormList(String rowId, E dto) throws IllegalAccessException {
        List<TFormValue> formValues = new ArrayList<>();
        LocalDateTime localDateTime= LocalDateTime.now();
        for(Field field: fields){
            TFormValue v = new TFormValue();
            v.setRowId(rowId);
            v.setTableName(tableName);
            v.setField(field.getName());
            v.setValue(String.valueOf(field.get(dto)));
            v.setCreateTime(localDateTime);
            formValues.add(v);
        }
        return formValues;
    }

    public List<E> getFormList(List<TFormValue> list) {
        List<E> data = new ArrayList<>();
        list.stream().collect(
                Collectors.groupingBy(
                        TFormValue::getRowId,
                        Collectors.toMap(
                                TFormValue::getField, TFormValue::getValue,(t1,t2)->t1
                        )
                )
        ).forEach(
                (rowId, map)->{
                    try {
                        E bannerDto =  this.tClass.newInstance();
                        for(Field field: fields){
                            if (field.getType().equals(Integer.class)){
                                field.set(bannerDto, Integer.valueOf(map.getOrDefault(field.getName(), "0")));
                            } else if (field.getType().equals(String.class)){
                                field.set(bannerDto, map.getOrDefault(field.getName(), ""));
                            }
                            setRowId(field, bannerDto, rowId);
                        }
                        data.add(bannerDto);
//                        int i = 1/0;
                    } catch (InstantiationException | IllegalAccessException e) {
                        throw new RuntimeException(e);
                    }
                }
        );
        return data;
    }

    public List<TFormValue> getUpdateFormList(List<TFormValue> formRow, E dto) throws IllegalAccessException {
        int i = 0;
        LocalDateTime localDateTime = LocalDateTime.now();
        for(Field field: fields){
            TFormValue v;
            if (i < formRow.size()){
                v = formRow.get(i);
            }else {
                v = new TFormValue();
                v.setCreateTime(localDateTime);
                v.setRowId(getRowId(dto));
                formRow.add(v);
            }
            v.setTableName(tableName);
            v.setField(field.getName());
            v.setValue(String.valueOf(field.get(dto)));
            i++;
        }
        return formRow;
    }

    private void setRowId(Field field, Object obj, String rowId) throws IllegalAccessException {
        if (field.getName().equals(AbsDynamicService.rowId)){
            field.set(obj, rowId);
        }
    }

    private String getRowId(Object obj) throws IllegalAccessException {
        return rowIdField.get(obj).toString();
    }

    /**
     * obj形成表单数据，排除空字符串
     *
     * @param o o
     * @return {@link List}<{@link TFormValue}>
     * @throws IllegalAccessException 非法访问异常
     */
    public List<TFormValue> objToFormValue(E o) throws IllegalAccessException {
        List<TFormValue> list = new ArrayList<>();
        for(Field field: fields){
            TFormValue v = new TFormValue();
            v.setTableName(tableName);
            v.setField(field.getName());
            Object obj = field.get(o);
            if (Objects.nonNull(obj)){
                String value = String.valueOf(obj);
                v.setValue(value);
                list.add(v);
            }
        }
        return list;
    }

    public static String humpToUnderline(String str) {
        String regex = "([A-Z])";
        Matcher matcher = Pattern.compile(regex).matcher(str);
        while (matcher.find()) {
            String target = matcher.group();
            str = str.replaceAll(target, "_"+target.toLowerCase());
        }
        return str;
    }

}
